﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace PayloadTracker.APRS.Parsers
{
    public class GPGGA : IParser
    {
        /*
             $GPGGA

             Global Positioning System Fix Data

             eg1. $GPGGA,170834,4124.8963,N,08151.6838,W,1,05,1.5,280.2,M,-34.0,M,,,*75

             Name    Example Data    Description
             Sentence Identifier     $GPGGA  Global Positioning System Fix Data
             Time    170834  17:08:34 UTC
             Latitude        4124.8963, N    41d 24.8963' N or 41d 24' 54" N
             Longitude       08151.6838, W   81d 51.6838' W or 81d 51' 41" W
             Fix Quality:
             - 0 = Invalid
             - 1 = GPS fix
             - 2 = DGPS fix  1       Data is from a GPS fix
             Number of Satellites    05      5 Satellites are in view
             Horizontal Dilution of Precision (HDOP) 1.5     Relative accuracy of horizontal position
             Altitude        280.2, M        280.2 meters above mean sea level
             Height of geoid above WGS84 ellipsoid   -34.0, M        -34.0 meters
             Time since last DGPS update     blank   No last update
             DGPS reference station id       blank   No station id
             Checksum        *75     Used by program to check for transmission errors
        */

        enum GPGGAParts : int
        {
            SENTENCEIDENTIFIER = 0,
            UTCTIME = 1,
            LATITUDE = 2,
            LATITUDEBEARING = 3,
            LONGITUDE = 4,
            LONGITUDEBEARING = 5,
            FIXQUALITY = 6,
            NUMBEROFSAILITES = 7,
            HORIZONTALDILUTION = 8,
            ALTITUDE = 9,
            ALTITUDEUNIT = 10,
            GEOIDHEIGHT = 11,
            GEOIDHEIGHTUNIT = 12,
            TIMESINCELASTDGPSUPDATE = 13,
            DGPSREFERENCESTATIONID = 14,
            
        }

        public struct GPGGAExtraData
        {
            public string FixQuality;
            public string NumberofSatilites;
            public string HDOP;
        }


        public override APRSBeacon Parse(string sentence)
        {
            

            if (!IsValidSentance(sentence))
                throw new Exception("Invalid Sentence");

            var csv = sentence.Split(',');

            double Long = Tools.GPSToDecimalDegrees(csv[((int)GPGGAParts.LONGITUDE)], csv[((int)GPGGAParts.LONGITUDEBEARING)]);
            double Lat  = Tools.GPSToDecimalDegrees(csv[((int)GPGGAParts.LATITUDE)], csv[((int)GPGGAParts.LATITUDEBEARING)]);
            float Alt = Tools.MetersToFeet(float.Parse(csv[((int)GPGGAParts.ALTITUDE)]));
            
            DateTime Time = Tools.NMEAUTCTimeToUTCDateTime(csv[((int)GPGGAParts.UTCTIME)]);

            APRSBeacon ret = new APRSBeacon(string.Empty,new Coordinate(Lat,Long),Time,Alt);
            return ret;
        }
        public GPGGAExtraData GetExtraData(string sentence)
        {
            if (!IsValidSentance(sentence))
                throw new Exception("Invalid Sentence");
            
            var csv = sentence.Split(',');
            GPGGAExtraData data = new GPGGAExtraData();

            data.FixQuality = csv[((int)GPGGAParts.FIXQUALITY)];
            data.HDOP = csv[((int)GPGGAParts.HORIZONTALDILUTION)];
            data.NumberofSatilites = csv[((int)GPGGAParts.NUMBEROFSAILITES)];

            return data;
        }

        public override bool IsValidSentance(string sentence)
        {
            if (!sentence.StartsWith("$GPGGA"))
                return false;

            //Checksum
            int crc = Convert.ToByte(sentence[1]);
            for (int i = 2; i < sentence.Length-3; i++)
                crc ^= Convert.ToByte(sentence[i]);

            return sentence.EndsWith("*" + crc.ToString("X2"));

        }
    }
}
